the next nine commits
squashing 36 commits into one giant commit
Create twitter_favorite agent

Agent that returns favorite tweet of given user

Added history, number and clean up

'history' is buffer to hold historical tweet.id this can be used for memory optimization, 'number' is number of latest tweets that Agent retrieve.

Update to use Array, Clean code, renamed

I put Array into 'memory' to make it simpler, that clean up some not needed code. Hope it will be included to make it more wide used.

Fix'd typos

Fix'd typos #2

Fix'd ref on null object

Fixed `undefined method `include' for nil:NilClass`

Added Pocket variable

Added POCKET_OAUTH_KEY for Pocket support

Adding first scraps

pocket_concerns.rb scrap

something for pocket

Added Pocket gem

Revert "Added Pocket gem"

This reverts commit 701ecd5393b05a8926dba9e45834592dd09774ef.

Revert "pocket_concerns.rb scrap"

This reverts commit cd1b3a751dcb3ca6f36746cfddb23b3e889fb986.

Revert "Adding first scraps"

This reverts commit 4e63b1302364218d46c062f915e1023e63886f43.

Revert "Added Pocket variable"

This reverts commit bb390680bb7bfd6cb424a283d7103dbd15966538.

renamed file with agent to make file names consistent

added in factory girl and disabled master fixture replacement

some work on spec file

spec one fail one success

rm factory girl

cleaner specs

twitter favorites spec half done

deleted extra agent

comment out one of the test

twitter favorite specs

a more proper date

changed back to starting at

fixed number to history typo

altered memory in agent

shifting memory down by one instead of halfing memory last seen

removed typo

replaced all mockobject with agent

fixed indentation issue

setting up event payload information and switched to tectonic

asserted payload looks what it is suppose to

reduced 5 events to 1 event

updated tweets json and spec file

checking out my db schema

rm date from options

rm last test

removed saved from check method

put back last spec and test passed

changed date make it change by 3 instead

moved memory shifting into the loop

moved memory last seen outside of the loop

Michał (Gore) Półrolniczak 8 anos atrás
pai
commit
70919fc24e

+ 87 - 0
app/models/agents/twitter_favorites.rb

@@ -0,0 +1,87 @@
1
+module Agents
2
+  class TwitterFavorites < Agent
3
+    include TwitterConcern
4
+
5
+    cannot_receive_events!
6
+
7
+    description <<-MD
8
+      The Twitter Favorites List Agent follows the favorites list of a specified Twitter user.
9
+      #{twitter_dependencies_missing if dependencies_missing?}
10
+      To be able to use this Agent you need to authenticate with Twitter in the [Services](/services) section first.
11
+      You must also provide the `username` of the Twitter user, `number` of latest tweets to monitor and `history' as number of tweets that will be held in memory.
12
+      Set `expected_update_period_in_days` to the maximum amount of time that you'd expect to pass between Events being created by this Agent.
13
+      Set `starting_at` to the date/time (eg. `Mon Jun 02 00:38:12 +0000 2014`) you want to start receiving tweets from (default: agent's `created_at`)
14
+    MD
15
+
16
+    event_description <<-MD
17
+      Events are the raw JSON provided by the [Twitter API](https://dev.twitter.com/docs/api/1.1/get/favorites/list). Should look something like:
18
+          {
19
+             ... every Tweet field, including ...
20
+            "text": "something",
21
+            "user": {
22
+              "name": "Mr. Someone",
23
+              "screen_name": "Someone",
24
+              "location": "Vancouver BC Canada",
25
+              "description":  "...",
26
+              "followers_count": 486,
27
+              "friends_count": 1983,
28
+              "created_at": "Mon Aug 29 23:38:14 +0000 2011",
29
+              "time_zone": "Pacific Time (US & Canada)",
30
+              "statuses_count": 3807,
31
+              "lang": "en"
32
+            },
33
+            "retweet_count": 0,
34
+            "entities": ...
35
+            "lang": "en"
36
+          }
37
+    MD
38
+
39
+    default_schedule "every_1h"
40
+
41
+    def working?
42
+      event_created_within?(interpolated['expected_update_period_in_days']) && !recent_error_logs?
43
+    end
44
+
45
+    def default_options
46
+      {
47
+        'username' => 'tectonic',
48
+        'number' => '10',
49
+        'history' => '100',
50
+        'expected_update_period_in_days' => '2'
51
+      }
52
+    end
53
+
54
+     def validate_options
55
+      errors.add(:base, "username is required") unless options['username'].present?
56
+      errors.add(:base, "number is required") unless options['number'].present?
57
+      errors.add(:base, "history is required") unless options['history'].present?
58
+      errors.add(:base, "expected_update_period_in_days is required") unless options['expected_update_period_in_days'].present?
59
+
60
+      if options[:starting_at].present?
61
+        Time.parse(options[:starting_at]) rescue errors.add(:base, "Error parsing starting_at")
62
+      end
63
+    end
64
+
65
+    def starting_at
66
+      if interpolated[:starting_at].present?
67
+        Time.parse(interpolated[:starting_at]) rescue created_at
68
+      else
69
+        created_at
70
+      end
71
+    end
72
+
73
+    def check
74
+      opts = {:count => interpolated['number']}
75
+      tweets = twitter.favorites(interpolated['username'], opts)
76
+      memory[:last_seen] ||= []
77
+
78
+      tweets.each do |tweet|
79
+        unless memory[:last_seen].include?(tweet.id) || tweet.created_at < starting_at
80
+          memory[:last_seen].push(tweet.id)
81
+          memory[:last_seen].shift if memory[:last_seen].length > interpolated['history'].to_i
82
+          create_event payload: tweet.attrs
83
+        end
84
+      end
85
+    end
86
+  end
87
+end

+ 98 - 0
spec/data_fixtures/one_fav_tweet.json

@@ -0,0 +1,98 @@
1
+
2
+
3
+{
4
+  "created_at": "Fri Feb 19 16:40:30 +0000 2016",
5
+  "id": 700721633040830464,
6
+  "id_str": "700721633040830464",
7
+  "text": "@tectonic this is everything I've been afraid of",
8
+  "source": "<a href=\"http://twitter.com/download/iphone\" rel=\"nofollow\">Twitter for iPhone<\/a>",
9
+  "truncated": false,
10
+  "in_reply_to_status_id": 700718619555024896,
11
+  "in_reply_to_status_id_str": "700718619555024896",
12
+  "in_reply_to_user_id": 9813372,
13
+  "in_reply_to_user_id_str": "9813372",
14
+  "in_reply_to_screen_name": "tectonic",
15
+  "user": {
16
+    "id": 285822802,
17
+    "id_str": "285822802",
18
+    "name": "Maryam Labib",
19
+    "screen_name": "labibti",
20
+    "location": "225",
21
+    "description": "founder @humansofthemsa, coder @pivotal, alum @cal, funny @twitter, blessing @theworld.",
22
+    "url": null,
23
+    "entities": {
24
+      "description": {
25
+        "urls": [
26
+
27
+        ]
28
+      }
29
+    },
30
+    "protected": false,
31
+    "followers_count": 364,
32
+    "friends_count": 278,
33
+    "listed_count": 10,
34
+    "created_at": "Thu Apr 21 21:10:56 +0000 2011",
35
+    "favourites_count": 1453,
36
+    "utc_offset": -28800,
37
+    "time_zone": "Pacific Time (US & Canada)",
38
+    "geo_enabled": false,
39
+    "verified": false,
40
+    "statuses_count": 3083,
41
+    "lang": "en",
42
+    "contributors_enabled": false,
43
+    "is_translator": false,
44
+    "is_translation_enabled": false,
45
+    "profile_background_color": "FF6699",
46
+    "profile_background_image_url": "http://pbs.twimg.com/profile_background_images/593311458/fnfdvrer7wu731vxbjoo.jpeg",
47
+    "profile_background_image_url_https": "https://pbs.twimg.com/profile_background_images/593311458/fnfdvrer7wu731vxbjoo.jpeg",
48
+    "profile_background_tile": false,
49
+    "profile_image_url": "http://pbs.twimg.com/profile_images/675612479427219457/j9YB0-6x_normal.jpg",
50
+    "profile_image_url_https": "https://pbs.twimg.com/profile_images/675612479427219457/j9YB0-6x_normal.jpg",
51
+    "profile_banner_url": "https://pbs.twimg.com/profile_banners/285822802/1449910573",
52
+    "profile_link_color": "3B94D9",
53
+    "profile_sidebar_border_color": "CC3366",
54
+    "profile_sidebar_fill_color": "D4C8CB",
55
+    "profile_text_color": "362720",
56
+    "profile_use_background_image": true,
57
+    "has_extended_profile": false,
58
+    "default_profile": false,
59
+    "default_profile_image": false,
60
+    "following": false,
61
+    "follow_request_sent": false,
62
+    "notifications": false
63
+  },
64
+  "geo": null,
65
+  "coordinates": null,
66
+  "place": null,
67
+  "contributors": null,
68
+  "is_quote_status": false,
69
+  "retweet_count": 0,
70
+  "favorite_count": 1,
71
+  "entities": {
72
+    "hashtags": [
73
+
74
+    ],
75
+    "symbols": [
76
+
77
+    ],
78
+    "user_mentions": [
79
+      {
80
+        "screen_name": "tectonic",
81
+        "name": "Andrew Cantino",
82
+        "id": 9813372,
83
+        "id_str": "9813372",
84
+        "indices": [
85
+          0,
86
+          9
87
+        ]
88
+      }
89
+    ],
90
+    "urls": [
91
+
92
+    ]
93
+  },
94
+  "favorited": false,
95
+  "retweeted": false,
96
+  "lang": "en"
97
+}
98
+

+ 701 - 0
spec/data_fixtures/user_fav_tweets.json

@@ -0,0 +1,701 @@
1
+
2
+[
3
+{
4
+  "created_at": "Fri Feb 19 18:08:04 +0000 2016",
5
+  "id": 700743667217207299,
6
+  "id_str": "700743667217207299",
7
+  "text": "Set up Huginn to track higher-tier rewards on Indiegogo campaigns because I'm too nice to tell them to leave",
8
+  "source": "<a href=\"http://stevencrewniverse.tumblr.com\" rel=\"nofollow\">RoseGem<\/a>",
9
+  "truncated": false,
10
+  "in_reply_to_status_id": null,
11
+  "in_reply_to_status_id_str": null,
12
+  "in_reply_to_user_id": null,
13
+  "in_reply_to_user_id_str": null,
14
+  "in_reply_to_screen_name": null,
15
+  "user": {
16
+    "id": 3010753754,
17
+    "id_str": "3010753754",
18
+    "name": "Streza_eBooks",
19
+    "screen_name": "streza_ebooks",
20
+    "location": "",
21
+    "description": "Constant bit rater. Fan of space bars, animated GIFs, cookies, and floating-points. Member of the MBR Fan Club. Aggressive header. Processor for now. Bit/byte.",
22
+    "url": "https://t.co/W0zvIPlUnC",
23
+    "entities": {
24
+      "url": {
25
+        "urls": [
26
+          {
27
+            "url": "https://t.co/W0zvIPlUnC",
28
+            "expanded_url": "http://twitter.com/SteveStreza",
29
+            "display_url": "twitter.com/SteveStreza",
30
+            "indices": [
31
+              0,
32
+              23
33
+            ]
34
+          }
35
+        ]
36
+      },
37
+      "description": {
38
+        "urls": [
39
+
40
+        ]
41
+      }
42
+    },
43
+    "protected": false,
44
+    "followers_count": 126,
45
+    "friends_count": 113,
46
+    "listed_count": 31,
47
+    "created_at": "Fri Feb 06 02:43:56 +0000 2015",
48
+    "favourites_count": 2464,
49
+    "utc_offset": null,
50
+    "time_zone": null,
51
+    "geo_enabled": false,
52
+    "verified": false,
53
+    "statuses_count": 28548,
54
+    "lang": "en",
55
+    "contributors_enabled": false,
56
+    "is_translator": false,
57
+    "is_translation_enabled": false,
58
+    "profile_background_color": "C0DEED",
59
+    "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png",
60
+    "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png",
61
+    "profile_background_tile": false,
62
+    "profile_image_url": "http://pbs.twimg.com/profile_images/672957162151387136/OpClSkjl_normal.jpg",
63
+    "profile_image_url_https": "https://pbs.twimg.com/profile_images/672957162151387136/OpClSkjl_normal.jpg",
64
+    "profile_banner_url": "https://pbs.twimg.com/profile_banners/3010753754/1423193197",
65
+    "profile_link_color": "0084B4",
66
+    "profile_sidebar_border_color": "C0DEED",
67
+    "profile_sidebar_fill_color": "DDEEF6",
68
+    "profile_text_color": "333333",
69
+    "profile_use_background_image": true,
70
+    "has_extended_profile": false,
71
+    "default_profile": true,
72
+    "default_profile_image": false,
73
+    "following": false,
74
+    "follow_request_sent": false,
75
+    "notifications": false
76
+  },
77
+  "geo": null,
78
+  "coordinates": null,
79
+  "place": null,
80
+  "contributors": null,
81
+  "is_quote_status": false,
82
+  "retweet_count": 0,
83
+  "favorite_count": 1,
84
+  "entities": {
85
+    "hashtags": [
86
+
87
+    ],
88
+    "symbols": [
89
+
90
+    ],
91
+    "user_mentions": [
92
+
93
+    ],
94
+    "urls": [
95
+
96
+    ]
97
+  },
98
+  "favorited": false,
99
+  "retweeted": false,
100
+  "lang": "en"
101
+},
102
+
103
+{
104
+  "created_at": "Sat Feb 20 01:32:08 +0000 2016",
105
+  "id": 700855422643621889,
106
+  "id_str": "700855422643621889",
107
+  "text": "@tectonic Another word for ?????????",
108
+  "source": "<a href=\"http://twitterrific.com\" rel=\"nofollow\">Twitterrific<\/a>",
109
+  "truncated": false,
110
+  "in_reply_to_status_id": 700854882161438720,
111
+  "in_reply_to_status_id_str": "700854882161438720",
112
+  "in_reply_to_user_id": 9813372,
113
+  "in_reply_to_user_id_str": "9813372",
114
+  "in_reply_to_screen_name": "tectonic",
115
+  "user": {
116
+    "id": 12884962,
117
+    "id_str": "12884962",
118
+    "name": "Nicolas Ward",
119
+    "screen_name": "UltraNurd",
120
+    "location": "Vancouver, WA",
121
+    "description": "Gainfully employed NLP and machine learning geek by day. Husby of best wifelet @Andrle. Father of cutest Theodore. I like books, games, and politics. Lutheran",
122
+    "url": "https://t.co/Ja3DWptYIn",
123
+    "entities": {
124
+      "url": {
125
+        "urls": [
126
+          {
127
+            "url": "https://t.co/Ja3DWptYIn",
128
+            "expanded_url": "http://blog.ultranurd.net",
129
+            "display_url": "blog.ultranurd.net",
130
+            "indices": [
131
+              0,
132
+              23
133
+            ]
134
+          }
135
+        ]
136
+      },
137
+      "description": {
138
+        "urls": [
139
+
140
+        ]
141
+      }
142
+    },
143
+    "protected": false,
144
+    "followers_count": 1209,
145
+    "friends_count": 1218,
146
+    "listed_count": 118,
147
+    "created_at": "Wed Jan 30 20:25:59 +0000 2008",
148
+    "favourites_count": 17135,
149
+    "utc_offset": -18000,
150
+    "time_zone": "Eastern Time (US & Canada)",
151
+    "geo_enabled": true,
152
+    "verified": false,
153
+    "statuses_count": 69702,
154
+    "lang": "en",
155
+    "contributors_enabled": false,
156
+    "is_translator": false,
157
+    "is_translation_enabled": false,
158
+    "profile_background_color": "C6E2EE",
159
+    "profile_background_image_url": "http://abs.twimg.com/images/themes/theme2/bg.gif",
160
+    "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme2/bg.gif",
161
+    "profile_background_tile": false,
162
+    "profile_image_url": "http://pbs.twimg.com/profile_images/701114865436332032/upPSPR2u_normal.png",
163
+    "profile_image_url_https": "https://pbs.twimg.com/profile_images/701114865436332032/upPSPR2u_normal.png",
164
+    "profile_banner_url": "https://pbs.twimg.com/profile_banners/12884962/1440017042",
165
+    "profile_link_color": "1F98C7",
166
+    "profile_sidebar_border_color": "C6E2EE",
167
+    "profile_sidebar_fill_color": "DAECF4",
168
+    "profile_text_color": "663B12",
169
+    "profile_use_background_image": true,
170
+    "has_extended_profile": false,
171
+    "default_profile": false,
172
+    "default_profile_image": false,
173
+    "following": false,
174
+    "follow_request_sent": false,
175
+    "notifications": false
176
+  },
177
+  "geo": null,
178
+  "coordinates": null,
179
+  "place": null,
180
+  "contributors": null,
181
+  "is_quote_status": false,
182
+  "retweet_count": 0,
183
+  "favorite_count": 1,
184
+  "entities": {
185
+    "hashtags": [
186
+
187
+    ],
188
+    "symbols": [
189
+
190
+    ],
191
+    "user_mentions": [
192
+      {
193
+        "screen_name": "tectonic",
194
+        "name": "Andrew Cantino",
195
+        "id": 9813372,
196
+        "id_str": "9813372",
197
+        "indices": [
198
+          0,
199
+          9
200
+        ]
201
+      }
202
+    ],
203
+    "urls": [
204
+
205
+    ]
206
+  },
207
+  "favorited": false,
208
+  "retweeted": false,
209
+  "lang": "en"
210
+},
211
+
212
+{
213
+  "created_at": "Sat Feb 20 03:40:03 +0000 2016",
214
+  "id": 700887613352255490,
215
+  "id_str": "700887613352255490",
216
+  "text": "University of Texas allows guns on campus and San Francisco State bans hoverboards. Gotta love humans. https://t.co/t98Z7ATR8Q",
217
+  "source": "<a href=\"http://twitter.com/download/iphone\" rel=\"nofollow\">Twitter for iPhone<\/a>",
218
+  "truncated": false,
219
+  "in_reply_to_status_id": null,
220
+  "in_reply_to_status_id_str": null,
221
+  "in_reply_to_user_id": null,
222
+  "in_reply_to_user_id_str": null,
223
+  "in_reply_to_screen_name": null,
224
+  "user": {
225
+    "id": 285822802,
226
+    "id_str": "285822802",
227
+    "name": "Maryam Labib",
228
+    "screen_name": "labibti",
229
+    "location": "225",
230
+    "description": "founder @humansofthemsa, coder @pivotal, alum @cal, funny @twitter, blessing @theworld.",
231
+    "url": null,
232
+    "entities": {
233
+      "description": {
234
+        "urls": [
235
+
236
+        ]
237
+      }
238
+    },
239
+    "protected": false,
240
+    "followers_count": 366,
241
+    "friends_count": 279,
242
+    "listed_count": 10,
243
+    "created_at": "Thu Apr 21 21:10:56 +0000 2011",
244
+    "favourites_count": 1454,
245
+    "utc_offset": -28800,
246
+    "time_zone": "Pacific Time (US & Canada)",
247
+    "geo_enabled": false,
248
+    "verified": false,
249
+    "statuses_count": 3084,
250
+    "lang": "en",
251
+    "contributors_enabled": false,
252
+    "is_translator": false,
253
+    "is_translation_enabled": false,
254
+    "profile_background_color": "FF6699",
255
+    "profile_background_image_url": "http://pbs.twimg.com/profile_background_images/593311458/fnfdvrer7wu731vxbjoo.jpeg",
256
+    "profile_background_image_url_https": "https://pbs.twimg.com/profile_background_images/593311458/fnfdvrer7wu731vxbjoo.jpeg",
257
+    "profile_background_tile": false,
258
+    "profile_image_url": "http://pbs.twimg.com/profile_images/675612479427219457/j9YB0-6x_normal.jpg",
259
+    "profile_image_url_https": "https://pbs.twimg.com/profile_images/675612479427219457/j9YB0-6x_normal.jpg",
260
+    "profile_banner_url": "https://pbs.twimg.com/profile_banners/285822802/1449910573",
261
+    "profile_link_color": "3B94D9",
262
+    "profile_sidebar_border_color": "CC3366",
263
+    "profile_sidebar_fill_color": "D4C8CB",
264
+    "profile_text_color": "362720",
265
+    "profile_use_background_image": true,
266
+    "has_extended_profile": false,
267
+    "default_profile": false,
268
+    "default_profile_image": false,
269
+    "following": false,
270
+    "follow_request_sent": false,
271
+    "notifications": false
272
+  },
273
+  "geo": null,
274
+  "coordinates": null,
275
+  "place": null,
276
+  "contributors": null,
277
+  "quoted_status_id": 700877581361532930,
278
+  "quoted_status_id_str": "700877581361532930",
279
+  "quoted_status": {
280
+    "created_at": "Sat Feb 20 03:00:11 +0000 2016",
281
+    "id": 700877581361532930,
282
+    "id_str": "700877581361532930",
283
+    "text": "San Francisco State University bans hoverboards https://t.co/flQ7BmEAki https://t.co/4KjztcWDId",
284
+    "source": "<a href=\"http://www.hootsuite.com\" rel=\"nofollow\">Hootsuite<\/a>",
285
+    "truncated": false,
286
+    "in_reply_to_status_id": null,
287
+    "in_reply_to_status_id_str": null,
288
+    "in_reply_to_user_id": null,
289
+    "in_reply_to_user_id_str": null,
290
+    "in_reply_to_screen_name": null,
291
+    "user": {
292
+      "id": 16664681,
293
+      "id_str": "16664681",
294
+      "name": "Los Angeles Times",
295
+      "screen_name": "latimes",
296
+      "location": "Los Angeles, CA",
297
+      "description": "News from Los Angeles and the world. Staffed by http://t.co/zb8HyvYyAJ editors.",
298
+      "url": "http://t.co/JvbZRDfNzf",
299
+      "entities": {
300
+        "url": {
301
+          "urls": [
302
+            {
303
+              "url": "http://t.co/JvbZRDfNzf",
304
+              "expanded_url": "http://latimes.com/",
305
+              "display_url": "latimes.com",
306
+              "indices": [
307
+                0,
308
+                22
309
+              ]
310
+            }
311
+          ]
312
+        },
313
+        "description": {
314
+          "urls": [
315
+            {
316
+              "url": "http://t.co/zb8HyvYyAJ",
317
+              "expanded_url": "http://latimes.com",
318
+              "display_url": "latimes.com",
319
+              "indices": [
320
+                48,
321
+                70
322
+              ]
323
+            }
324
+          ]
325
+        }
326
+      },
327
+      "protected": false,
328
+      "followers_count": 1799021,
329
+      "friends_count": 10737,
330
+      "listed_count": 26340,
331
+      "created_at": "Thu Oct 09 11:07:42 +0000 2008",
332
+      "favourites_count": 1724,
333
+      "utc_offset": -28800,
334
+      "time_zone": "Pacific Time (US & Canada)",
335
+      "geo_enabled": true,
336
+      "verified": true,
337
+      "statuses_count": 129068,
338
+      "lang": "en",
339
+      "contributors_enabled": false,
340
+      "is_translator": false,
341
+      "is_translation_enabled": false,
342
+      "profile_background_color": "FFFFFF",
343
+      "profile_background_image_url": "http://pbs.twimg.com/profile_background_images/596769492/sp4uqn6gr7cwmjefat2j.jpeg",
344
+      "profile_background_image_url_https": "https://pbs.twimg.com/profile_background_images/596769492/sp4uqn6gr7cwmjefat2j.jpeg",
345
+      "profile_background_tile": false,
346
+      "profile_image_url": "http://pbs.twimg.com/profile_images/546329819919560704/XMWy2Z50_normal.jpeg",
347
+      "profile_image_url_https": "https://pbs.twimg.com/profile_images/546329819919560704/XMWy2Z50_normal.jpeg",
348
+      "profile_banner_url": "https://pbs.twimg.com/profile_banners/16664681/1402448809",
349
+      "profile_link_color": "009999",
350
+      "profile_sidebar_border_color": "FFFFFF",
351
+      "profile_sidebar_fill_color": "EFEFEF",
352
+      "profile_text_color": "615F61",
353
+      "profile_use_background_image": true,
354
+      "has_extended_profile": false,
355
+      "default_profile": false,
356
+      "default_profile_image": false,
357
+      "following": false,
358
+      "follow_request_sent": false,
359
+      "notifications": false
360
+    },
361
+    "geo": null,
362
+    "coordinates": null,
363
+    "place": null,
364
+    "contributors": null,
365
+    "is_quote_status": false,
366
+    "retweet_count": 80,
367
+    "favorite_count": 87,
368
+    "entities": {
369
+      "hashtags": [
370
+
371
+      ],
372
+      "symbols": [
373
+
374
+      ],
375
+      "user_mentions": [
376
+
377
+      ],
378
+      "urls": [
379
+        {
380
+          "url": "https://t.co/flQ7BmEAki",
381
+          "expanded_url": "http://lat.ms/1WxgJpV",
382
+          "display_url": "lat.ms/1WxgJpV",
383
+          "indices": [
384
+            48,
385
+            71
386
+          ]
387
+        }
388
+      ],
389
+      "media": [
390
+        {
391
+          "id": 700877581084659712,
392
+          "id_str": "700877581084659712",
393
+          "indices": [
394
+            72,
395
+            95
396
+          ],
397
+          "media_url": "http://pbs.twimg.com/media/CboEclOWEAAbjEW.jpg",
398
+          "media_url_https": "https://pbs.twimg.com/media/CboEclOWEAAbjEW.jpg",
399
+          "url": "https://t.co/4KjztcWDId",
400
+          "display_url": "pic.twitter.com/4KjztcWDId",
401
+          "expanded_url": "http://twitter.com/latimes/status/700877581361532930/photo/1",
402
+          "type": "photo",
403
+          "sizes": {
404
+            "small": {
405
+              "w": 680,
406
+              "h": 383,
407
+              "resize": "fit"
408
+            },
409
+            "large": {
410
+              "w": 700,
411
+              "h": 394,
412
+              "resize": "fit"
413
+            },
414
+            "thumb": {
415
+              "w": 150,
416
+              "h": 150,
417
+              "resize": "crop"
418
+            },
419
+            "medium": {
420
+              "w": 700,
421
+              "h": 394,
422
+              "resize": "fit"
423
+            }
424
+          }
425
+        }
426
+      ]
427
+    },
428
+    "extended_entities": {
429
+      "media": [
430
+        {
431
+          "id": 700877581084659712,
432
+          "id_str": "700877581084659712",
433
+          "indices": [
434
+            72,
435
+            95
436
+          ],
437
+          "media_url": "http://pbs.twimg.com/media/CboEclOWEAAbjEW.jpg",
438
+          "media_url_https": "https://pbs.twimg.com/media/CboEclOWEAAbjEW.jpg",
439
+          "url": "https://t.co/4KjztcWDId",
440
+          "display_url": "pic.twitter.com/4KjztcWDId",
441
+          "expanded_url": "http://twitter.com/latimes/status/700877581361532930/photo/1",
442
+          "type": "photo",
443
+          "sizes": {
444
+            "small": {
445
+              "w": 680,
446
+              "h": 383,
447
+              "resize": "fit"
448
+            },
449
+            "large": {
450
+              "w": 700,
451
+              "h": 394,
452
+              "resize": "fit"
453
+            },
454
+            "thumb": {
455
+              "w": 150,
456
+              "h": 150,
457
+              "resize": "crop"
458
+            },
459
+            "medium": {
460
+              "w": 700,
461
+              "h": 394,
462
+              "resize": "fit"
463
+            }
464
+          }
465
+        }
466
+      ]
467
+    },
468
+    "favorited": false,
469
+    "retweeted": false,
470
+    "possibly_sensitive": false,
471
+    "lang": "en"
472
+  },
473
+  "is_quote_status": true,
474
+  "retweet_count": 6,
475
+  "favorite_count": 7,
476
+  "entities": {
477
+    "hashtags": [
478
+
479
+    ],
480
+    "symbols": [
481
+
482
+    ],
483
+    "user_mentions": [
484
+
485
+    ],
486
+    "urls": [
487
+      {
488
+        "url": "https://t.co/t98Z7ATR8Q",
489
+        "expanded_url": "https://twitter.com/latimes/status/700877581361532930",
490
+        "display_url": "twitter.com/latimes/status…",
491
+        "indices": [
492
+          103,
493
+          126
494
+        ]
495
+      }
496
+    ]
497
+  },
498
+  "favorited": false,
499
+  "retweeted": false,
500
+  "possibly_sensitive": false,
501
+  "lang": "en"
502
+},
503
+
504
+{
505
+  "created_at": "Tue Feb 23 16:12:04 +0000 2016",
506
+  "id": 702164029163220993,
507
+  "id_str": "702164029163220993",
508
+  "text": "I didn't even realize how islamophobic the U.S. was till Donald Trump threatened to deport Muslims to get votes. https://t.co/WKyoMl7ux8",
509
+  "source": "<a href=\"http://twitter.com/download/iphone\" rel=\"nofollow\">Twitter for iPhone<\/a>",
510
+  "truncated": false,
511
+  "in_reply_to_status_id": null,
512
+  "in_reply_to_status_id_str": null,
513
+  "in_reply_to_user_id": null,
514
+  "in_reply_to_user_id_str": null,
515
+  "in_reply_to_screen_name": null,
516
+  "user": {
517
+    "id": 285822802,
518
+    "id_str": "285822802",
519
+    "name": "Maryam Labib",
520
+    "screen_name": "labibti",
521
+    "location": "225",
522
+    "description": "founder @humansofthemsa, coder @pivotal, alum @cal, funny @twitter, blessing @theworld.",
523
+    "url": null,
524
+    "entities": {
525
+      "description": {
526
+        "urls": [
527
+
528
+        ]
529
+      }
530
+    },
531
+    "protected": false,
532
+    "followers_count": 366,
533
+    "friends_count": 279,
534
+    "listed_count": 10,
535
+    "created_at": "Thu Apr 21 21:10:56 +0000 2011",
536
+    "favourites_count": 1454,
537
+    "utc_offset": -28800,
538
+    "time_zone": "Pacific Time (US & Canada)",
539
+    "geo_enabled": false,
540
+    "verified": false,
541
+    "statuses_count": 3084,
542
+    "lang": "en",
543
+    "contributors_enabled": false,
544
+    "is_translator": false,
545
+    "is_translation_enabled": false,
546
+    "profile_background_color": "FF6699",
547
+    "profile_background_image_url": "http://pbs.twimg.com/profile_background_images/593311458/fnfdvrer7wu731vxbjoo.jpeg",
548
+    "profile_background_image_url_https": "https://pbs.twimg.com/profile_background_images/593311458/fnfdvrer7wu731vxbjoo.jpeg",
549
+    "profile_background_tile": false,
550
+    "profile_image_url": "http://pbs.twimg.com/profile_images/675612479427219457/j9YB0-6x_normal.jpg",
551
+    "profile_image_url_https": "https://pbs.twimg.com/profile_images/675612479427219457/j9YB0-6x_normal.jpg",
552
+    "profile_banner_url": "https://pbs.twimg.com/profile_banners/285822802/1449910573",
553
+    "profile_link_color": "3B94D9",
554
+    "profile_sidebar_border_color": "CC3366",
555
+    "profile_sidebar_fill_color": "D4C8CB",
556
+    "profile_text_color": "362720",
557
+    "profile_use_background_image": true,
558
+    "has_extended_profile": false,
559
+    "default_profile": false,
560
+    "default_profile_image": false,
561
+    "following": false,
562
+    "follow_request_sent": false,
563
+    "notifications": false
564
+  },
565
+  "geo": null,
566
+  "coordinates": null,
567
+  "place": null,
568
+  "contributors": null,
569
+  "quoted_status_id": 702148755395649536,
570
+  "quoted_status_id_str": "702148755395649536",
571
+  "quoted_status": {
572
+    "created_at": "Tue Feb 23 15:11:23 +0000 2016",
573
+    "id": 702148755395649536,
574
+    "id_str": "702148755395649536",
575
+    "text": "The US ruins the Middle East, creates an environment where immigrants see it necessary to come to America, then is overtly islamophobic.",
576
+    "source": "<a href=\"http://twitter.com/download/android\" rel=\"nofollow\">Twitter for Android<\/a>",
577
+    "truncated": false,
578
+    "in_reply_to_status_id": 702148012051714049,
579
+    "in_reply_to_status_id_str": "702148012051714049",
580
+    "in_reply_to_user_id": 427904994,
581
+    "in_reply_to_user_id_str": "427904994",
582
+    "in_reply_to_screen_name": "HalfAtlanta",
583
+    "user": {
584
+      "id": 427904994,
585
+      "id_str": "427904994",
586
+      "name": "Huey P.",
587
+      "screen_name": "HalfAtlanta",
588
+      "location": "Atlanta, GA",
589
+      "description": "Hasta la victoria de África siempre. Organizer. I'm navigating a post-Zaynist world one direct action at a time...☭",
590
+      "url": "https://t.co/kvMUv6Mlvj",
591
+      "entities": {
592
+        "url": {
593
+          "urls": [
594
+            {
595
+              "url": "https://t.co/kvMUv6Mlvj",
596
+              "expanded_url": "http://urbansoulatlanta.com",
597
+              "display_url": "urbansoulatlanta.com",
598
+              "indices": [
599
+                0,
600
+                23
601
+              ]
602
+            }
603
+          ]
604
+        },
605
+        "description": {
606
+          "urls": [
607
+
608
+          ]
609
+        }
610
+      },
611
+      "protected": false,
612
+      "followers_count": 2641,
613
+      "friends_count": 401,
614
+      "listed_count": 39,
615
+      "created_at": "Sun Dec 04 03:32:00 +0000 2011",
616
+      "favourites_count": 27377,
617
+      "utc_offset": -21600,
618
+      "time_zone": "Central Time (US & Canada)",
619
+      "geo_enabled": true,
620
+      "verified": false,
621
+      "statuses_count": 27248,
622
+      "lang": "en",
623
+      "contributors_enabled": false,
624
+      "is_translator": false,
625
+      "is_translation_enabled": false,
626
+      "profile_background_color": "000000",
627
+      "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png",
628
+      "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png",
629
+      "profile_background_tile": false,
630
+      "profile_image_url": "http://pbs.twimg.com/profile_images/694036432898396160/xRofldlh_normal.jpg",
631
+      "profile_image_url_https": "https://pbs.twimg.com/profile_images/694036432898396160/xRofldlh_normal.jpg",
632
+      "profile_banner_url": "https://pbs.twimg.com/profile_banners/427904994/1451575667",
633
+      "profile_link_color": "9266CC",
634
+      "profile_sidebar_border_color": "FFFFFF",
635
+      "profile_sidebar_fill_color": "000000",
636
+      "profile_text_color": "CF40CF",
637
+      "profile_use_background_image": true,
638
+      "has_extended_profile": true,
639
+      "default_profile": false,
640
+      "default_profile_image": false,
641
+      "following": false,
642
+      "follow_request_sent": false,
643
+      "notifications": false
644
+    },
645
+    "geo": null,
646
+    "coordinates": null,
647
+    "place": null,
648
+    "contributors": null,
649
+    "is_quote_status": false,
650
+    "retweet_count": 33,
651
+    "favorite_count": 37,
652
+    "entities": {
653
+      "hashtags": [
654
+
655
+      ],
656
+      "symbols": [
657
+
658
+      ],
659
+      "user_mentions": [
660
+
661
+      ],
662
+      "urls": [
663
+
664
+      ]
665
+    },
666
+    "favorited": false,
667
+    "retweeted": false,
668
+    "lang": "en"
669
+  },
670
+  "is_quote_status": true,
671
+  "retweet_count": 13,
672
+  "favorite_count": 15,
673
+  "entities": {
674
+    "hashtags": [
675
+
676
+    ],
677
+    "symbols": [
678
+
679
+    ],
680
+    "user_mentions": [
681
+
682
+    ],
683
+    "urls": [
684
+      {
685
+        "url": "https://t.co/WKyoMl7ux8",
686
+        "expanded_url": "https://twitter.com/halfatlanta/status/702148755395649536",
687
+        "display_url": "twitter.com/halfatlanta/st…",
688
+        "indices": [
689
+          113,
690
+          136
691
+        ]
692
+      }
693
+    ]
694
+  },
695
+  "favorited": false,
696
+  "retweeted": false,
697
+  "possibly_sensitive": false,
698
+  "lang": "en"
699
+}
700
+
701
+]

+ 14 - 0
spec/fixtures/agents.yml

@@ -94,6 +94,20 @@ bob_twitter_user_agent:
94 94
       :oauth_token_secret => "---"
95 95
     }.to_json.inspect %>
96 96
 
97
+tectonic_twitter_user_agent:
98
+  type: Agents::TwitterFavorites
99
+  user: tectonic
100
+  name: "tectonic's Twitter Favorites Watcher"
101
+  guid: <%= SecureRandom.hex %>
102
+  options: <%= {
103
+      :username => "tectonic",
104
+      :expected_update_period_in_days => "2",
105
+      :consumer_key => "---",
106
+      :consumer_secret => "---",
107
+      :oauth_token => "---",
108
+      :oauth_token_secret => "---"
109
+    }.to_json.inspect %>
110
+
97 111
 bob_manual_event_agent:
98 112
   type: Agents::ManualEventAgent
99 113
   user: bob

+ 50 - 0
spec/models/agents/twitter_favorites_spec.rb

@@ -0,0 +1,50 @@
1
+require 'rails_helper'
2
+
3
+describe Agents::TwitterFavorites do
4
+  before do
5
+    stub_request(:any, /tectonic/).to_return(body: File.read(Rails.root.join("spec/data_fixtures/user_fav_tweets.json")), status: 200)
6
+  end
7
+
8
+  before do
9
+
10
+    @opts = {:username => "tectonic", :number => "10", :history => "100", :expected_update_period_in_days => "2", :starting_at => "Sat Feb 20 01:32:08 +0000 2016"}
11
+
12
+    @agent = Agents::TwitterFavorites.new(name: "tectonic", options: @opts)
13
+    @agent.service = services(:generic)
14
+    @agent.events.new(payload: JSON.parse(File.read(Rails.root.join("spec/data_fixtures/one_fav_tweet.json"))))
15
+    @agent.user = users(:bob)
16
+    @agent.save!
17
+
18
+    @event = Event.new
19
+    @event.agent = agents(:tectonic_twitter_user_agent)
20
+    @event.payload = JSON.parse(File.read(Rails.root.join("spec/data_fixtures/one_fav_tweet.json")))
21
+    @event.save!
22
+  end
23
+
24
+  describe "making sure agent last event payload is equivalent to event payload" do
25
+    it "expect change method to change event" do
26
+      expect(@agent.events.last.payload).to eq(@event.payload)
27
+    end
28
+  end
29
+
30
+  describe "making sure check method works" do
31
+
32
+    it "expect change method to change event" do
33
+     expect { @agent.check }.to change {Event.count}.by(3)
34
+    end
35
+  end
36
+
37
+  describe "#check with starting_at=future date" do
38
+
39
+    it "should check for changes starting_at a future date, thus not find any" do
40
+      opts = @opts.merge({ starting_at: "Thurs Feb 23 16:12:04 +0000 2017" })
41
+
42
+      @agent1 = Agents::TwitterFavorites.new(name: "tectonic", options: opts)
43
+      @agent1.service = services(:generic)
44
+      @agent1.user = users(:bob)
45
+      @agent1.save!
46
+
47
+      expect { @agent1.check }.to change { Event.count }.by(0)
48
+    end
49
+  end
50
+end